<template>
  <div class="container">
    <div class="canvas-wrap" ref="canvasWrapRef">
      <!-- 所有元素以图片中心为参考系 -->
      <!-- :offsetX="stageConfig.offsetX"
        :offsetY="stageConfig.offsetY" -->
      <v-stage
        __useStrictMode
        ref="stage"
        :x="stageConfig.x"
        :y="stageConfig.y"
        :config="{
          width: stageConfig.width,
          height: stageConfig.height,
        }"
        :offsetX="stageConfig.offsetX"
        :offsetY="stageConfig.offsetY"
        :rotation="stageConfig.rotation"
        :scaleX="stageConfig.scale"
        :scaleY="stageConfig.scale"
        :draggable="draggable"
        @dragmove="handleStageDragMove"
        @mousedown="handleMouseDown"
        @mousemove="handleMouseMove"
        @mouseup="handleMouseUp"
      >
        <v-layer>
          <v-image
            :image="imageDom"
            :x="image.x"
            :y="image.y"
            :width="image.width"
            :height="image.height"
          />
          <div v-for="rect in rectList">
            <v-rect
              :x="rect.x"
              :y="rect.y"
              :width="rect.width"
              :height="rect.height"
              :fill="'rgba(0,0,0,0)'"
              :stroke="'red'"
              :strokeWidth="2"
            />
          </div>
          <!-- 坐标轴 -->
          <div>
            <v-line
              v-for="line in xAxisList"
              :key="line.x"
              :points="[
                line.x,
                line.y,
                line.x,
                line.y + line.height,
              ]"
              :stroke="'#ccc'"
              :strokeWidth="1"
            />
            <v-text
              v-for="text in xAxisTextList"
              :key="text.x"
              :x="text.x"
              :y="text.y"
              align="center"
              :text="text.text"
            />
            <v-line
              v-for="line in yAxisList"
              :key="line.y"
              :points="[
                line.x,
                line.y,
                line.x + line.width,
                line.y,
              ]"
              :stroke="'#ccc'"
              :strokeWidth="1"
            />
            <v-text
              v-for="text in yAxisTextList"
              :key="text.y"
              :x="text.x"
              :y="text.y"
              align="center"
              :text="text.text"
            />
            <v-line
              :points="[
                stageConfig.x - stageConfig.width / 2,
                stageConfig.y,
                stageConfig.x + stageConfig.width / 2,
                stageConfig.y,
              ]"
              :stroke="'#000'"
              :strokeWidth="1"
            />
            <v-line
              :points="[
                stageConfig.x,
                stageConfig.y - stageConfig.height / 2,
                stageConfig.x,
                stageConfig.y + stageConfig.height / 2,
              ]"
              :stroke="'#000'"
              :strokeWidth="1"
            />
          </div>
        </v-layer>
      </v-stage>
    </div>
  </div>
</template>

<script>
export default {
  name: "prev-img",
  props: {
    draggable: {
      type: Boolean,
      default: true,
    },
  },
  data() {
    return {
      drawing: false,
      imageSrc:
        "https://oss.xinjiaoyu.com/exam/test/182769/10237/20230413_64aacbb1995a4d91b8a1ef8342518af5_36/20230413_64aacbb1995a4d91b8a1ef8342518af5_36_001_page.jpg",
      imageDom: new Image(),
      // 画布配置
      stageConfig: {
        x: 0,
        y: 0,
        width: 500,
        height: 300,
        offsetX: 0,
        offsetY: 0,
        scale: 1,
        rotation: 0,
      },
      initImageScale: 1,
      // 图片配置
      image: {
        x: 0,
        y: 0,
        width: 0,
        height: 0,
      },
      // 框选配置
      rectList: [],
      // 坐标系配置
      xAxisList: [],
      xAxisTextList: [],
      yAxisList: [],
      yAxisTextList: [],
    };
  },
  created() {
    this.imageDom.src = this.imageSrc;
    this.imageDom.crossOrigin = "anonymous";
    this.imageDom.onload = () => {
      this.reset();
      this.initKeyBoardEvent();
      this.initMouseEvent();
      this.addCoordinate();
    };
  },
  methods: {
    // 旋转
    rotate(angle) {
      this.stageConfig.rotation += angle;
    },
    // 缩放
    zoom(scale) {
      const res = this.stageConfig.scale + scale;
      if (res < 0.1) return;
      this.stageConfig.scale += scale;
      console.log("缩放", this.stageConfig.scale);
    },
    handleMouseDown(event) {
      if (this.draggable) return;
      // 获取鼠标相对于stage的位置
      const { x, y } = mousePosToStagePos(event, this.stageConfig);
      this.drawing = true;
      this.rectList.push({
        x: x * this.stageConfig.scale,
        y: y * this.stageConfig.scale,
        width: 100,
        height: 100,
      });
    },
    handleMouseMove(event) {
      if (this.draggable || !this.drawing) return;
    },
    handleMouseUp(event) {
      if (this.draggable) return;
      this.drawing = false;
      // const rect = this.rectList[this.rectList.length - 1];
      // if (Math.abs(rect.width) < 5 || Math.abs(rect.height) < 5) {
      //   this.rectList.pop();
      //   console.log("框选区域过小");
      // } else {
      //   // 删除当前矩形，修改为缩放后的矩形
      //   this.rectList.pop();
      //   this.rectList.push({
      //     x: rect.x / this.stageConfig.scale,
      //     y: rect.y / this.stageConfig.scale,
      //     width: rect.width / this.stageConfig.scale,
      //     height: rect.height / this.stageConfig.scale,
      //   });
      // }
    },
    handleStageDragMove(event) {
      const offsetX = event.evt.movementX;
      const offsetY = event.evt.movementY;
      this.stageConfig.x += offsetX;
      this.stageConfig.y += offsetY;
    },
    drawRect(event) {
      const { x, y } = mousePosToStagePos(event, this.stageConfig);
      const rect = this.rectList[this.rectList.length - 1];
      rect.width = x - rect.x;
      rect.height = y - rect.y;
    },
    reset() {
      // 设置画布宽高
      const { width, height } =
        this.$refs.canvasWrapRef.getBoundingClientRect();
      Object.assign(this.stageConfig, {
        x: width / 2,
        y: height / 2,
        width,
        height,
        offsetX: width / 2,
        offsetY: height / 2,
        scale: 1,
        rotation: 0,
      });

      // 初始化图片大小
      const {
        width: imageWidth,
        height: imageHeight,
        scale,
      } = initImageSize(this.imageDom, this.stageConfig);
      this.initImageScale = scale;
      this.image = {
        x: (width - imageWidth) / 2,
        y: (height - imageHeight) / 2,
        width: imageWidth,
        height: imageHeight,
      };
    },
    // 注册键盘事件
    initKeyBoardEvent() {
      window.addEventListener("keydown", (event) => {
        const { key } = event;
        console.log(key);
        switch (key) {
          case "ArrowLeft":
            this.stageConfig.x -= 10;
            break;
          case "ArrowRight":
            this.stageConfig.x += 10;
            break;
          case "ArrowUp":
            this.stageConfig.y -= 10;
            break;
          case "ArrowDown":
            this.stageConfig.y += 10;
            break;
          case "Backspace":
            break;
          default:
            break;
        }
      });
    },
    // 注册滑轮事件
    initMouseEvent() {
      const stage = this.$refs.stage.getStage();
      stage.addEventListener("wheel", (event) => {
        const { deltaY } = event;
        if (deltaY > 0) {
          this.zoom(-0.1);
        } else {
          this.zoom(0.1);
        }
      });
    },
    // 添加坐标线
    addCoordinate() {
      const unit = 50;
      const { x, y, width, height } = this.stageConfig;
      const xAxisLength = width / unit;
      const yAxisHeight = height / unit;
      for (let i = 0; i < xAxisLength; i++) {
        this.xAxisList.push({
          x: x - width / 2 + i * unit,
          y: y - height / 2,
          width: 1,
          height: height,
        });
        this.xAxisTextList.push({
          x: x - width / 2 + i * unit,
          y: y - height / 2 + 10,
          text: i * unit,
        });
      }
      for (let i = 0; i < yAxisHeight; i++) {
        this.yAxisList.push({
          x: x - width / 2,
          y: y - height / 2 + i * unit,
          width: width,
          height: 1,
        });
        this.yAxisTextList.push({
          x: x - width / 2 + 10,
          y: y - height / 2 + i * unit,
          text: i * unit || '',
        });
      }

    },
  },
};

/**
 * 鼠标坐标转换为stage坐标
 * @param {Object} event 鼠标事件
 * @param {Object} stageConfig 画布配置
 */
function mousePosToStagePos(event, stageConfig) {
  const { offsetX, offsetY } = event.evt;
  const { x, y, width, height, scale, offsetX: offsetX1, offsetY: offsetY1 } = stageConfig;
  console.log("鼠标坐标", offsetX, offsetY, x-width/2);
  // 鼠标相当于stage位置
  return {
    x: (offsetX - (x - width / 2)) / scale,
    y: offsetY - (y - height / 2),
    // x: offsetX,
    // y: offsetY,
  };

}

/**
 * 将canvas坐标转换为图片中心坐标
 * @param {Object} canvas canvas坐标
 * @param {Object} center 图片中心坐标
 */
function canvasPosToImageCenter(canvas, center) {
  return {
    x: center.x - canvas.x,
    y: center.y - canvas.y,
  };
}

/**
 * 根据矩形偏移量和宽高获取矩形四个顶点相对于中心点的坐标
 * @param {Object} rect 矩形
 */
function getRectPoints(rect) {
  const { offsetX: x, offsetY: y, width, height } = rect;
  return [
    { x, y },
    { x: x - width, y },
    { x: x - width, y: y - height },
    { x, y: y - height },
  ];
}

/**
 * 获取矩形左上角偏移量，width和height可以为负数
 * @param {Object} rect 矩形
 */
function getRectLeftTop(rect) {
  const { offsetX, offsetY, width, height } = rect;
  return {
    offsetX: width > 0 ? offsetX : offsetX - width,
    offsetY: height > 0 ? offsetY : offsetY - height,
  };
}

/**
 * 初始化图片大小
 * @param {Object} imageDom 图片宽高
 * @param {Object} stageConfig 画布宽高
 */
function initImageSize(imageDom, stageConfig) {
  const { width, height } = imageDom;
  console.log("原图大小", width, height);
  const { width: stageWidth, height: stageHeight } = stageConfig;
  const scaleX = stageWidth / width;
  const scaleY = stageHeight / height;
  const scale = Math.min(scaleX, scaleY);
  return {
    width: width * scale,
    height: height * scale,
    scale,
  };
}
</script>

<style scoped lang="scss">
.container {
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  .canvas-wrap {
    flex: 1;
    border: 1px solid#ccc;
  }
}
</style>
